package MathCore;

import MathCore.Operands.Complex;
import MathCore.Operands.List;
import MathCore.Operands.Number;
import MathCore.Operands.Variable;
import MathCore.Operators.OperatorException;

public abstract class Operator extends Lexeme
{
	public Operator(){}

	abstract public Operand exec(Operand operands[]) throws OperatorException;
	abstract public int params();
	abstract public int priority();

	// проверка на любой тип
	public static boolean only(Operand params[], Class cls)
	{
		for(int i=0; i<params.length; i++)
		{
			if(!cls.isInstance(params[i]))
			{
				return false;
			}
		}
		return true;
	}

	// проверка на наличие
	public static boolean have(Operand params[], Class cls)
	{
		for(int i=0; i<params.length; i++)
		{
			if(cls.isInstance(params[i]))
			{
				return true;
			}
		}
		return false;
	}

	// развертывание коплексных чисел
	public static Operand[] expandNumbersToComplex(Operand params[])
	{
		for(int i=0; i<params.length; i++)
		{
			if(params[i] instanceof Number)
			{
				params[i] = new Complex(((Number)params[i]).get(), Real.ZERO, Complex.RE_IM);
			}
		}
		return params;
	}

	// одномерное (линейное) развертывание списков
	public static Operand expandListsLinear(Operand params[], Operator target) throws OperatorException
	{
		int minlen = Integer.MAX_VALUE;

		for(int i=0; i<params.length; i++)
		{
			if(params[i] instanceof List && ((List)params[i]).size() < minlen)
			{
				minlen = ((List)params[i]).size();
			}
		}

		Operand rparams[] = new Operand[params.length];

		for(int i=0; i<params.length; i++)
		{
			if(params[i] instanceof List)
			{
				rparams[i] = params[i];
			}
			else
			{
				List replace = new List();
				replace.fill(params[i], minlen);
				rparams[i] = replace;
			}
		}
		// теперь в	rparams	лежат только списки


		/*	rparams[]:
		 *									1 2 3 4 5 6 7 8 9
		 *									1 2 3 4 5
		 *									1 2 3 4 5 6 7
		 * этот список был развернут ->		3 3 3 3 3
		 *									        ^ - минимальная длина
		 * если сложение, то result:		6 9 12 15 18
		 *
		 * */

		List result = new List();
		Operand expanded[] = new Operand[params.length];

		for(int i=0; i<minlen; i++)
		{
			for(int j=0; j<params.length; j++)
			{
				expanded[j] = ((List)rparams[j]).get(i);
			}
			result.add(target.exec(expanded));
		}

		return result;
	}
}
